//
//  HTTPAPI.m
//  AccountEasy
//
//  Created by mac on 2020/7/22.
//  Copyright © 2020 AccountEasy. All rights reserved.
//

#import "HTTPAPI.h"
#import "AFNetworking.h"
#import "MBProgressHUD.h"
#import "Prompt.h"
#import "MBProgressHUD+GoGoFun.h"
#import "LPActivityIndicatorView.h"
#import "NSObject+JsonString.h"
#import "NSString+MD5.h"
#import "Alert.h"
#include <sys/time.h>
#include <sys/sysctl.h>
#import "NSString+nonce.h"
#import "NSString+MD5.h"
#import "SALoginVC.h"

@interface HTTPAPI ()

@property (strong, nonatomic) AFHTTPSessionManager *manager;
@property (strong, nonatomic) MBProgressHUD *progressHUD;

@end

@implementation HTTPAPI

- (NSDictionary *)parameters {
    
    NSArray *propertyList = [self propertyList];
    NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc] initWithCapacity:propertyList.count];
    for(NSString *property in propertyList) {
        NSArray *arr = [self valueForKey:property];
        if ([[self valueForKey:property] isKindOfClass:[NSNull class]] ||
            (![self valueForKey:property])) {
            continue;
        }else if([[self valueForKey:property] isKindOfClass:[NSArray class]] && arr.count) {
            mutableDict[property] = [[self valueForKey:property] jsonString];
        }else {
            [mutableDict setValue:[self valueForKeyPath:property] forKeyPath:property];
        }
    }
    
    if (self.coverParameters) {
        [mutableDict addEntriesFromDictionary:(self.coverParameters)];
    }
    
    //签名认证，用来校验传给后台的数据是否被更改，签名规则看文档，只是多传参数给后台，不会对任何接口造成影响
    //如出现签名认证失败才需要改动，不然被动
    //MD5 和 加密一些算法已经调好，如果需要新项目，建议把现在的MD5文件拷过去
    NSString *timestamp = KTimestamp;
    NSString *nonce = [NSString random:32];
    mutableDict[@"timestamp"] = timestamp;
    mutableDict[@"nonce"] = nonce;
    NSString *strdeviceId = [kDeviceId stringByReplacingOccurrencesOfString:@"-" withString:@""];
    mutableDict[@"deviceId"] = strdeviceId;
    mutableDict[@"sign"] = [self getSign:mutableDict];
    return mutableDict;
}

- (NSString *)url {
    
    NSString *url = [NSString stringWithFormat:@"%@:%@/%@", self.serverAddr, self.serverPort, self.methodName];
    return url;
}

- (NSString *)methodName
{
    [self createExceptionWithMsg:NSStringFromSelector(_cmd)];
    return nil;
}

- (NSString *)serverAddr
{
    return kServerHost;
}

- (NSString *)serverPort
{
    return kServerPort;
}

#pragma mark GET 请求

+(void)GET:(NSString *)URLString parameters:(id)parameters success:(void (^)(NSURLSessionDataTask * task, id responseObject))success failure:(void (^)(NSURLSessionDataTask * task, NSError *error))failure{
    
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    
    //设置请求类型
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/html", @"text/plain",nil];
    
    
    [manager GET:URLString parameters:parameters headers:nil progress:nil success:success failure:failure];
}

+(void)POST:(NSString *)URLString parameters:(id)parameters success:(void (^)(NSURLSessionDataTask * task, id responseObject))success failure:(void (^)(NSURLSessionDataTask * task, NSError *error))failure{
    
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    //设置请求类型
    [manager.responseSerializer setAcceptableContentTypes:[NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/html", @"text/plain",nil]];
    
    [manager POST:URLString parameters:parameters headers:nil progress:nil success:success failure:failure];
}

- (void)sendRequestToServerWithType:(RequestType)type
{
    [self sendRequestToServerWithType:type showActivityIndicatorOnView:nil];
}

- (void)sendRequestToServerWithActivityViewAndMask:(RequestType)type
{
    [LPActivityIndicatorView showWithMask];
    [self sendRequestToServerWithType:type showActivityIndicatorOnView:nil];
}

- (void)sendRequestToServerWithType:(RequestType)type showActivityIndicatorOnView:(UIView *)view
{
    if (view)
    {
        [LPActivityIndicatorView showOnView:view];
    }
    _requestType = type;
    self.manager.requestSerializer.timeoutInterval = 15;
    self.manager.requestSerializer = [AFJSONRequestSerializer serializer];
    [self.manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    self.manager.responseSerializer = [AFJSONResponseSerializer serializer];
    self.manager.responseSerializer.acceptableContentTypes  = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html", nil];
    [AFJSONResponseSerializer serializer].removesKeysWithNullValues = YES;
    
    void (^SuccessBlock)(NSURLSessionDataTask *dataTask, id dataObj) = ^(NSURLSessionDataTask *dataTask, id dataObj)
    {
        [LPActivityIndicatorView hide];
        
        [self handleResponseDataObj:dataObj];
    };
    
    void (^FailedBlock)(NSURLSessionDataTask *dataTask, NSError *error) = ^(NSURLSessionDataTask *dataTask, NSError *error){
        
        if ([self.delegate respondsToSelector:@selector(fetchDataFromServerFailedWithError:API:)])
        {
            [LPActivityIndicatorView hide];
            NSInteger code = error.code;
            if (code == -1001) {
                [self ExitLogin];
                [Prompt popPromptViewWithMsg:@"网络不给力" duration:2];
                return;
            }
            [self.delegate fetchDataFromServerFailedWithError:error API:self];
            if (self.isPromptErrorMessage == YES) {
                [Prompt popPromptViewWithMsg:error.localizedDescription duration:3.f];
            }
        }
    };
    
    if (type == GET)
    {
        self.dataTask = [self.manager GET:self.url parameters:self.parameters headers:nil  progress:^(NSProgress * _Nonnull downloadProgress) {} success:SuccessBlock failure:FailedBlock];
    }
    else if (type == POST)
    {
        self.dataTask = [self.manager POST:self.url parameters:self.parameters headers:nil  progress:^(NSProgress * _Nonnull downloadProgress){} success:SuccessBlock failure:FailedBlock];
    }
}

- (void)sendServerImageData:(UIImage *)image
{
    if (!image) {
        return;
    }
    
    self.upImage = image;
    UIImage *originImage = image;
    NSData *imgData = UIImageJPEGRepresentation(originImage, 1.0f);
    NSString *encodedImageStr = [imgData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
    NSData *imageData = [[NSData alloc]initWithBase64EncodedString:encodedImageStr options:NSDataBase64DecodingIgnoreUnknownCharacters];
    
    NSDictionary *parameters = nil;
    
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    [manager.requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"];
    [manager.responseSerializer setAcceptableContentTypes:[NSSet setWithObjects:@"text/html",@"application/json", @"text/plain", nil]];
    
    [manager POST:self.url parameters:parameters headers:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        [formData appendPartWithFileData:imageData name:@"file" fileName:@"file.jpg" mimeType:@"image/jpg"];
    } progress:^(NSProgress * _Nonnull uploadProgress)
     {} success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject)
     {
        [self handleResponseDataObj:responseObject];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [Prompt popPromptViewWithMsg:error.localizedDescription duration:3.f];
    }];
}

- (void)OCRImageData:(NSArray<UIImage *> *)photos AndScale:(CGFloat)scale
{
    if (photos.count == 0) {
        return;
    }
    
//    NSData *imageData = UIImageJPEGRepresentation(photos[0], scale);
    
//    if (UIImageJPEGRepresentation(image, 1) != nil) {
//        imageData = UIImageJPEGRepresentation(image, scale);
//    } else {
//        imageData = UIImagePNGRepresentation (image);
//        fileName = @"file.png";
//        mimeType = @"image/png";
//    }
    
    NSDictionary *parameters = nil;
    
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    [manager.requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", @"multipart/form-data", @"application/json", @"text/html", @"image/jpeg", @"image/png", @"application/octet-stream", @"text/json", nil];
//    [manager.requestSerializer setTimeoutInterval:120.0];
    
//    NSString *contentLength = [NSString stringWithFormat:@"%zd",[imageData length]];
//    [manager.requestSerializer setValue:contentLength forHTTPHeaderField:@"Content-Length"];
    
    [manager POST:self.url parameters:parameters headers:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        int i = 0;
        for (UIImage *image in photos) {
            i++;
            NSData *imageData = UIImageJPEGRepresentation(image, scale);
            NSString *name = [NSString stringWithFormat:@"file%d",i];
            NSString *fileName = [NSString stringWithFormat:@"%@.jpeg",name];
            [formData appendPartWithFileData:imageData name:@"file" fileName:fileName mimeType:@"image/jpeg"];
        }
//        [formData appendPartWithFileData:imageData name:@"file" fileName:@"file1.jpeg" mimeType:@"image/jpeg"];
    } progress:^(NSProgress * _Nonnull uploadProgress)
     {} success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject)
     {
        [self handleResponseDataObj:responseObject];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [Prompt popPromptViewWithMsg:error.localizedDescription duration:3.f];
    }];
}

-(void)postDataWithUrl:(NSString *)url params:(NSMutableDictionary *)params imageDatas:(NSArray *)images success:(void (^)(id response))success failure:(void (^)(NSError *error))failure
{
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.responseSerializer = [AFJSONResponseSerializer serializer];
    [manager.requestSerializer setTimeoutInterval:60.0];
    [manager.requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"];
    [manager.responseSerializer setAcceptableContentTypes:[NSSet setWithObjects:@"application/json",@"text/html",@"text/javascript",@"text/xml",@"text/plain",nil]];
    if (self.url.length == 0) {
        self.url = url;
    }
    [manager POST:self.url parameters:params headers:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        for (UIImage *image in images) {

            // 在网络开发中，上传文件时，是文件不允许被覆盖，文件重名
            // 要解决此问题，
            // 可以在上传时使用当前的系统事件作为文件名
            NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
            // 设置时间格式
            formatter.dateFormat = @"yyyyMMddHHmmss";
            NSString *str = [formatter stringFromDate:[NSDate date]];
            NSString *fileName = [NSString stringWithFormat:@"%@.jpg", str];
            NSString *mimeType = @"image/jpg";
            // 图片太大会上传不到服务器上面去
            NSData *imageData = nil;
            if (UIImageJPEGRepresentation(image, 1)) {
                imageData = UIImageJPEGRepresentation(image, 0.5);
            }else {
                imageData = UIImagePNGRepresentation(image);
                fileName = [NSString stringWithFormat:@"%@.png", str];
                mimeType = @"image/png";
            }
            /*
             此方法参数
             1. 要上传的[二进制数据]
             2. 对应网站上[upload.php中]处理文件的[字段"file"]
             3. 要保存在服务器上的[文件名]
             4. 上传文件的[mimeType]
             */
            NSUInteger index = [images indexOfObject:image];
            if (index == images.count-1) {
                // 上传位置图片data
                [formData appendPartWithFileData:imageData name:@"files" fileName:fileName mimeType:mimeType];
            } else {
                [formData appendPartWithFileData:imageData name:@"files" fileName:fileName mimeType:mimeType];
            }
        }
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        success(responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        failure(error);
    }];
}

-(void)submitForm:(RequestType)type {
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    [manager.requestSerializer setValue:@"application/x-www-form-urlencoded; charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
    manager.requestSerializer = [AFHTTPRequestSerializer serializer];
    
    void (^SuccessBlock)(NSURLSessionDataTask *dataTask, id dataObj) = ^(NSURLSessionDataTask *dataTask, id dataObj)
    {
        [LPActivityIndicatorView hide];
        
        [self handleResponseDataObj:dataObj];
    };
    
    void (^FailedBlock)(NSURLSessionDataTask *dataTask, NSError *error) = ^(NSURLSessionDataTask *dataTask, NSError *error){
        
        if ([self.delegate respondsToSelector:@selector(fetchDataFromServerFailedWithError:API:)])
        {
            [LPActivityIndicatorView hide];
            [self.delegate fetchDataFromServerFailedWithError:error API:self];
            if (self.isPromptErrorMessage == YES) {
                [Prompt popPromptViewWithMsg:error.localizedDescription duration:3.f];
            }
        }
    };
    
    if (type == GET)
    {
        self.dataTask = [self.manager GET:self.url parameters:self.parameters headers:nil  progress:^(NSProgress * _Nonnull downloadProgress) {} success:SuccessBlock failure:FailedBlock];
    }
    else if (type == POST)
    {
        self.dataTask = [self.manager POST:self.url parameters:self.parameters headers:nil  progress:^(NSProgress * _Nonnull downloadProgress){} success:SuccessBlock failure:FailedBlock];
    }
}

-(NSInteger)now
{
    struct timeval now;
    struct timezone timeZ;
    gettimeofday(&now, &timeZ);
    return now.tv_sec;
}

- (NSInteger)bootTime
{
#define MIB_SIZE 2
    int mib[MIB_SIZE];
    size_t size;
    struct timeval  boottime;
    
    mib[0] = CTL_KERN;
    mib[1] = KERN_BOOTTIME;
    size = sizeof(boottime);
    if (sysctl(mib, MIB_SIZE, &boottime, &size, NULL, 0) != -1)
    {
        return boottime.tv_sec;
    }
    return 0;
}

- (void)sendRequestToServerWithType:(RequestType)type
          showActivityIndicatorView:(BOOL)show
{
    [LPActivityIndicatorView show];
}


+ (NSURLSessionDataTask *)requestWithRequestType:(RequestType)requestType
                                          method:(NSString *)method
                                      parameters:(NSDictionary *)parameters
                                    successBlock:(SuccessBlock)successBlock
                                     failedBlock:(FailedBlock)failedBlock
{
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain",@"text/html", @"application/json", nil];
    
    [manager.requestSerializer setValue:@"application/x-www-form-urlencoded;charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
    
    NSString *url = @"";
    
    void (^SuccessBlock)(NSURLSessionDataTask *task, id responseObject) = ^(NSURLSessionDataTask *task, id responseObject){
        
        if([responseObject[@"code"] intValue] == 0) {
            successBlock(task, responseObject[@"result"]);
        }
        else
        {
            NSError *error = [NSError errorWithDomain:@"服务器错误" code:[responseObject[@"code"] intValue] userInfo:@{@"mas":responseObject[@"msg"]}];
            failedBlock(task, error);
        }
    };
    
    void (^FailedBlock)(NSURLSessionDataTask *task, NSError *error) = ^(NSURLSessionDataTask *task, NSError *error){
        
        failedBlock(task, error);
    };
    
    if (requestType == GET)
    {
        return [manager GET:url parameters:parameters headers:nil  progress:^(NSProgress * _Nonnull downloadProgress) {} success:SuccessBlock failure:FailedBlock];
    }
    else if (requestType == POST)
    {
        return [manager POST:url parameters:parameters headers:nil  progress:^(NSProgress * _Nonnull uploadProgress) {} success:SuccessBlock failure:FailedBlock];
    }
    return nil;
}

#pragma mark 初始化API

+ (instancetype)apiWithDelegate:(id)object
{
    HTTPAPI *api = [self new];
    api.delegate = object;
    
    return api;
}

- (instancetype)init {
    if (self = [super init]) {
        self.isPromptErrorMessage = YES;
        self.isCode0Msg = YES;
    }
    return self;
}

#pragma mark Helper-Method

- (void)createExceptionWithMsg:(NSString*)msg
{
    [NSException raise:NSInternalInconsistencyException format:@"你必须要自己实现%@方法", msg];
}

/** 处理请求返回数据    */
- (void)handleResponseDataObj:(id)dataObj
{
    if ([dataObj[@"code"] integerValue] == 0)
    {
        if (self.delegate && [self.delegate respondsToSelector:@selector(fetchData:fromServerSuccessedWithAPI:)])
        {
            [self.delegate fetchData:dataObj fromServerSuccessedWithAPI:self];
        }
    }else if(self.delegate && [self.delegate respondsToSelector:@selector(fetchDataFromServerFailedWithError:API:)] && dataObj)
    {
        NSError *error = [[NSError alloc] initWithDomain:@"服务器内部错误" code:0 userInfo:dataObj];
        NSDictionary *dic = error.userInfo;
        if ([[NSString stringWithFormat:@"%@",dic[@"code"]] isEqualToString:@"901"]){
            NSString *message = dic[@"msg"];
            if (message.length == 0)  {
                message = @" ";
            }
            UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
            
            UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action) {
                [self ExitLogin];
            }];
            [alert addAction:okAction];
            [[self getCurrentVC] presentViewController:alert animated:true completion:nil];
        }else {
            if (self.isPromptErrorMessage == YES) {
                NSString *msg = [NSString stringWithFormat:@"%@",dic[@"msg"]];
                [Prompt popPromptViewWithMsg:msg duration:3];
            }
            [self.delegate fetchDataFromServerFailedWithError:error API:self];
        }
    }
}

- (AFHTTPSessionManager *)manager
{
    if (! _manager)
    {
        _manager = [AFHTTPSessionManager manager];
    }
    return _manager;
}

- (NSArray *)propertyList
{
    unsigned int count = 0;
    
    objc_property_t *properties = class_copyPropertyList([self class], &count);
    
    NSMutableArray *propertyList = [NSMutableArray new];
    
    for (int i = 0; i < count; i++)
    {
        [propertyList addObject:[NSString stringWithUTF8String:property_getName(*(properties + i))]];
    }
    free(properties);
    return propertyList;
}

//普通字符串转换为大写十六进制的。
- (NSString *)hexStringFromString:(NSString *)string{
    NSData *myD = [string dataUsingEncoding:NSUTF8StringEncoding];
    Byte *bytes = (Byte *)[myD bytes];
    //下面是Byte 转换为16进制。
    NSString *hexStr=@"";
    for(int i=0;i<[myD length];i++)
    {
        NSString *newHexStr = [NSString stringWithFormat:@"%x",bytes[i]&0xff];///16进制数
        if([newHexStr length]==1)
            hexStr = [NSString stringWithFormat:@"%@0%@",hexStr,newHexStr];
        else
            hexStr = [NSString stringWithFormat:@"%@%@",hexStr,newHexStr];
    }
    return hexStr;
}

- (NSString *)hexStringFromString2:(NSString *)string{
    NSData *myD = [string dataUsingEncoding:NSUTF8StringEncoding];
    Byte *bytes = (Byte *)[myD bytes];
    //下面是Byte 转换为16进制。
    NSString *hexStr=@"";
    for(int i=0;i<[myD length];i++) {
        NSString *newHexStr = [NSString stringWithFormat:@"%x",bytes[i]&0xff];///16进制数
        hexStr = [NSString stringWithFormat:@"%@%@",hexStr,newHexStr];
    }
    return hexStr;
}

//获取字典中的key字段,并且按照首字符从小到大排序
- (NSArray *)getkeyArrayFromDictionary:(NSDictionary *)dic{
    NSMutableArray *arr = [NSMutableArray array];
    [dic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        [arr addObject:key];
    }];
    NSComparator sort = ^(NSString *obj1,NSString *obj2){
        return [obj1 compare:obj2];
    };
    NSArray *resultArray = [arr sortedArrayUsingComparator:sort];
    return resultArray;
}

//获取签名 sign
-(NSString *)getSign:(NSMutableDictionary *)dic {
    SAUserInfo *model = [SAValueManger shareInStance].userInfo;
    NSString *modelSignKey = model.token;
    if (modelSignKey.length > 0 && ![self.methodName isEqualToString:@"/merchant/sendCode"]) {
        NSString *strdeviceId = [kDeviceId stringByReplacingOccurrencesOfString:@"-" withString:@""];
        NSString *sign = [NSString stringWithFormat:@"%@%@%@%@",model.empName,strdeviceId,dic[@"timestamp"],model.token];
        return [NSString stringToMD5:sign];
    }else{
        NSString *signKeyStr = [NSString stringWithFormat:@"%@#%@",dic[@"timestamp"],dic[@"nonce"]];
        NSString *signKeyMD5 =[NSString stringToMD5:signKeyStr];
        NSString *signKey = [signKeyMD5 uppercaseString];
        NSArray *keyArr = [self getkeyArrayFromDictionary:dic];
        NSMutableString *mStr = [NSMutableString string];
        [keyArr enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            [mStr appendFormat:@"%@", [NSString stringWithFormat:@"%@=%@&",obj,dic[obj]]];
        }];
        [mStr appendFormat:@"%@", [NSString stringWithFormat:@"key=%@",signKey]];
        return [NSString getHmacmd5:mStr withSecret:signKey];
    }
}

-(void)ExitLogin {
    [SAValueManger shareInStance].userInfo = nil;
    [kUserDefault setObject:@"" forKey:kAotuLoginKey];
    UIWindow *window =  [UIApplication sharedApplication].keyWindow;
    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[SALoginVC new]];
    window.rootViewController = nav;
    [window makeKeyAndVisible];
}

- (UIViewController *)getCurrentVC {
    UIViewController *result = nil;
    UIWindow * window = [[UIApplication sharedApplication] keyWindow];
    if (window.windowLevel != UIWindowLevelNormal) {
        NSArray *windows = [[UIApplication sharedApplication] windows];
        for(UIWindow * tmpWin in windows) {
            if (tmpWin.windowLevel == UIWindowLevelNormal) {
                window = tmpWin;
                break;
            }
        }
    }
    UIView *frontView = [[window subviews] objectAtIndex:0];
    id nextResponder = [frontView nextResponder];
    if ([nextResponder isKindOfClass:[UIViewController class]]) {
        result = nextResponder;
    } else {
        result = window.rootViewController;
    }
    return result;
}

@end
